﻿using System.Collections.Generic;
using System.Reflection;
using Carcassonne.Network;
using Sliver.Network.Components;
using Sliver.Network.IOC;
using UnityEngine;

namespace Sliver.Network.WebSocket
{
    public class WebSocketMessageDispatcher
    {
        protected Dictionary<string, object> Controllers;

        protected Dictionary<string, Dictionary<string, MethodInfo>> Functions =
            new Dictionary<string, Dictionary<string, MethodInfo>>();

        public WebSocketMessageDispatcher(Dictionary<string, object> controllers)
        {
            Controllers = controllers;
            foreach (var kv in controllers)
            {
                ReflectFunctions(kv.Key, kv.Value);
            }
        }

        public void ReflectFunctions(string path, object controller)
        {
            MethodInfo[] methods = controller.GetType().GetMethods();
            Dictionary<string, MethodInfo> functions = new Dictionary<string, MethodInfo>();
            foreach (MethodInfo method in methods)
            {
                WebSocketMessageHandler attr = method.GetCustomAttribute<WebSocketMessageHandler>();
                if (attr == null) continue;
                functions.Add(attr.Path, method);
            }

            Functions.Add(path, functions);
        }

        public void Dispatch(MessageIn message)
        {
            string path = message.path;

            if (path.StartsWith("/")) path = path.Substring(1);
            string[] route = path.Split('/');
            if (route.Length != 2)
            {
                return;
            }

            string controller = route[0];
            if (!Functions.ContainsKey(controller))
            {
                Debug.Log($"miss controller {controller}");
                return;
            }

            object sender = Controllers[controller];
            string method = route[1];
            Dictionary<string, MethodInfo> functions = Functions[controller];
            if (!functions.ContainsKey(method))
            {
                Debug.Log($"missing function '{controller}/{method}'");
                return;
            }

            MainThreadLoop.Add($"action_invoke_{method}", () =>
            {
                functions[method].Invoke(sender, new object[] { message });
            });
        }
    }
}